/******** Example Code : Accessing Atmel AT45Dxxx dataflash  *******

Device      : 	ATMEGA1281

File name   : 	dataflash.c

Description : 	Defines and prototypes for AT45Dxxx
                 
Last change:    14 Dec 2011   SN
 
****************************************************************************/


#include<avr/io.h>
#include<util/delay.h>
#include"spi.h"
#include"dataflash.h"
#include"usart.h"






#define FlashToBuf1Transfer 		0x53
#define FlashToBuf2Transfer 		0x55
#define Buf1Read			0xd4
/*****************************************************************************
*
*	Function name : send_status
*
*	Returns :		STATUS REGISTER CONTENTS
*
*	Parameters :		NONE
*
*	Purpose :		READ STATUS REGISTER TO VERIFY (CHECKED ON HARDWARE)
*					
******************************************************************************/



unsigned char send_status()
{
unsigned char k,j;
	k = SPI_transmit(0xD7);
	
	j = SPI_receive();
	
return j;
}


/*****************************************************************************
*
*	Function name : READ_BUFFER
*
*	Returns:	unsigned char	
*
*	Parameters :	Did explicitly gave address so made a generic one down
*
*	Purpose :	Reads a value from a particular address in the buffer(CHECKED ON HARDWARE)
*					
******************************************************************************/
unsigned char read_buffer(void)
{ //use the function knowing that buffer_counter is the value i hav to gve to read from that are of SRAM
	unsigned char buffer_counter;
	SPI_PORT |=(1<< SPI_CS);
	unsigned char j,k,l;
	SPI_PORT &= ~(1<< SPI_CS);
	j = send_status();
	
       		while(!((j==0xAC)|(j==0xEC)))
		{
		transmitString1("Error");
		j = send_status();
		}
	
		SPI_PORT |=(1<< SPI_CS);	
	
	  	SPI_PORT &= ~(1<< SPI_CS);

			k = SPI_transmit(0xd4);//Single Byte 0x00 to be sent to initiate read.
			
			k = SPI_transmit(0x00);
		
			k = SPI_transmit((unsigned char)(buffer_counter>>8));
	
			k = SPI_transmit((unsigned char)buffer_counter);
	
			k = SPI_transmit(0x00);//dont care conditions
	
			j = SPI_receive();
	
	        	return j;
}



/*****************************************************************************
*
*	Function name : write_buffer
*
*	Returns :	None
*
*	Parameters :	data to be written address expicitly specified
*
*	Purpose :	Writes a unsigned char into the buffer location (CHECKED ON HARDWARE)
*					
******************************************************************************/

void write_buffer(unsigned char data)
{  // use buffer counter to give  the memory location u wanna write too
 	uint16_t buffer_counter;
	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);

	unsigned char j,k,l,status;
	j = send_status();
	
		while(!((j==0xAC)|(j==0xEC)))
		{
		transmitString1("Error");
		j = send_status();
		
		}

		SPI_PORT |=(1<< SPI_CS);	
		SPI_PORT &= ~(1<< SPI_CS);
	
		k = SPI_transmit(0x84);
	
		k = SPI_transmit(0x00);
	
		k = SPI_transmit((unsigned char)(buffer_counter>>8));
	
		k = SPI_transmit((unsigned char)buffer_counter);
	
		k = SPI_transmit(data);
	
		SPI_PORT |=(1<< SPI_CS);	
		SPI_PORT &= ~(1<< SPI_CS);

		j = send_status();
		       while(!((j==0xAC)|(j==0xEC)))
			{
			transmitString1("Error");
			j = send_status();
			}
		
			SPI_PORT |=(1<< SPI_CS);
		

}


/*****************************************************************************
*
*	Function name : chip_erharase
*	Returns :	None
*
*	Parameters :	No parameters 
*
*	Purpose :	just erasing the entire the block (checked on the hardware)
*					
******************************************************************************/

void chip_erase()
{
	unsigned char k,j;
	SPI_PORT &= ~(1<< SPI_CS);

	k = SPI_transmit(0xC7);
	
	k = SPI_transmit(0x94);
	
	k = SPI_transmit(0X80);
	
	k = SPI_transmit(0X9A);

	SPI_PORT |=(1<< SPI_CS);
	SPI_PORT &= ~(1<< SPI_CS);
		j = send_status();
		while(!((j==0xAC)|(j==0xEC)))
		{
		transmitString1("Error");
		j = send_status();
		_delay_ms(200);
		}

}
/*****************************************************************************
*
*	Function name : buffer_memory
*
*	Returns :		None
*
*	Parameters :	
*
*	Purpose :		Transfers a data from buffer to memory(did not check)
*					
******************************************************************************/
void buffer_memory()
{
	uint16_t page_counter;
	unsigned char k,j;
	SPI_PORT &= ~(1<< SPI_CS);
	
	k = SPI_transmit(0x82);
	
	k = SPI_transmit((unsigned char)(page_counter>>6));
	
	k = SPI_transmit((unsigned char)(page_counter<<2));

	k = SPI_transmit(0x00);

	SPI_PORT |=(1<< SPI_CS);
	SPI_PORT &= ~(1<< SPI_CS);

	j = send_status();
//Use the following code for doing that
/*write_SPI(B1_TO_MM_PAGE_PROG_WITHOUT_ERASE);// write data from buffer1 to page 
            write_SPI((char)(page_counter>>6));
            write_SPI((char)(page_counter<<2));
            write_SPI(0x00);*/ 	
		while(!((j==0xAC)|(j==0xEC)))
		{
		transmitString1("Error");
		j = send_status();
		_delay_ms(200);
		}
}



// Used to erase blocks checked logically yet to write it on hardware lets see 
// Atmel datasheet code is wrong lets see?



void erasing(void) 
{
unsigned int block_counter = 0; //block counter which are 512 blocks used when large data is to be written ,
                                //will be used only in this function hope soo
unsigned char k;


while (block_counter < 512)
{
SPI_PORT &= ~(1<< SPI_CS); // enable DataFlash
k = SPI_transmit(0x50);
// wait for data transfer to be completed in error so have to check
k = SPI_transmit((char)(block_counter<<2));//SPDR = (char)(block_counter>>3);
// wait for data transfer to be completed
k = SPI_transmit((char)(block_counter>>6));//SPDR = (char)(block_counter<<5);
 // wait for data transfer to be completed
k = SPI_transmit(0x00);//SPDR = 0x00; // dont cares
 // wait for data transfer to be completed
SPI_PORT |=(1<< SPI_CS);// disable DataFlash
block_counter++;
} //disable SPI //has been taken out , only to check if error comes keep SPDR =0x00
}


/*****************************************************************************

*

*	Function name : Page_To_Buffer

*

*	Returns :		None

*

*	Parameters :	BufferNo	->	Decides usage of either buffer 1 or 2

*					PageAdr		->	Address of page to be transferred to buffer

*

*	Purpose :		Transfers a page from flash to dataflash SRAM buffer

*					

******************************************************************************/

void Page_To_Buffer (unsigned int PageAdr, unsigned char BufferNo)

{

	SPI_PORT |=(1<< SPI_CS);  //make sure to toggle CS signal in order

	SPI_PORT &= ~(1<< SPI_CS);	//	//to reset dataflash command decoder
	unsigned char k;										

										
	

	if (1 == BufferNo)											//transfer flash page to buffer 1

	{

		k = SPI_transmit(FlashToBuf1Transfer);	//transfer to buffer 1 op-code

		k = SPI_transmit((char)(PageAdr >> 6));//;DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));	//upper part of page address

		k = SPI_transmit((char)(PageAdr << 2));//DF_SPI_RW((unsigned char)(PageAdr << (PageBits - 8)));	//lower part of page address

		k = SPI_transmit(0x00)	;									//don't cares

	}

	else	

	if (2 == BufferNo)											//transfer flash page to buffer 2

	{

		k = SPI_transmit(FlashToBuf2Transfer);	//transfer to buffer 1 op-code

		k = SPI_transmit((char)(PageAdr >> 6));//;DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));	//upper part of page address

		k = SPI_transmit((char)(PageAdr << 2));//DF_SPI_RW((unsigned char)(PageAdr << (PageBits - 8)));	//lower part of page address

		k = SPI_transmit(0x00)	;											//don't cares

	}

	

	SPI_PORT |=(1<< SPI_CS);  //make sure to toggle CS signal in order

	SPI_PORT &= ~(1<< SPI_CS);	//	//to reset dataflash command decoder

	_delay_ms(200);
	_delay_ms(200);
		k = send_status();
	
		while(!((k==0xAC)|(k==0xEC)))
		{
		transmitString1("Error in Page to buffer");
		k = send_status();
		
		}
	//while(!(Read_DF_status() & 0x80));							//monitor the status register, wait until busy-flag is high

}

/*****************************************************************************

*

*	Function name : Buffer_Read_Byte

*

*	Returns :		One read byte (any value)

*

*	Parameters :	BufferNo	->	Decides usage of either buffer 1 or 2

*					IntPageAdr	->	Internal page address

*

*	Purpose :		Reads one byte from one of the dataflash

*					internal SRAM buffers

*

******************************************************************************/

unsigned char Buffer_Read_Byte (unsigned char BufferNo, unsigned int IntPageAdr)

{

	unsigned char data,k;

	
	SPI_PORT |=(1<< SPI_CS);  //make sure to toggle CS signal in order

	SPI_PORT &= ~(1<< SPI_CS);//to reset dataflash command decoder

	

	if (1 == BufferNo)							//read byte from buffer 1

	{

		
	k = SPI_transmit(0xd4);//Single Byte 0x00 to be sent to initiate read.
	
	k = SPI_transmit(0x00);
	
	k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
	k = SPI_transmit((unsigned char)IntPageAdr);
	
	k = SPI_transmit(0x00);//dont care conditions
	
	data = SPI_receive();
	
        				//read byte

	}

	else

	if (2 == BufferNo)							//read byte from buffer 2

	{
	k = SPI_transmit(0xd6);//Single Byte 0x00 to be sent to initiate read.
	
	k = SPI_transmit(0x00);
	
	k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
	k = SPI_transmit((unsigned char)IntPageAdr);
	
	k = SPI_transmit(0x00);//dont care conditions
	
	data = SPI_receive();

	}

		/*SPI_PORT |=(1<< SPI_CS);
		SPI_PORT &= ~(1<< SPI_CS);
		k = send_status();
		while(!((k==0xAC)|(k==0xEC)))
		{
		transmitString1("Error in reading  byte");
		k = send_status();
		_delay_ms(200);
		}
		SPI_PORT |=(1<< SPI_CS);
	*/

	return data;								//return the read data byte

}



/*****************************************************************************

*

*	Function name : Buffer_Read_Str

*

*	Returns :		None

*

*	Parameters :	BufferNo	->	Decides usage of either buffer 1 or 2
*					IntPageAdr	->	Internal page address
*					No_of_bytes	->	Number of bytes to be read
*					*BufferPtr	->	address of buffer to be used for read bytes
*
*	Purpose :		Reads one or more bytes from one of the dataflash
*					internal SRAM buffers, and puts read bytes into
*					buffer pointed to by *BufferPtr
*
******************************************************************************/

void Buffer_Read_Str (unsigned char BufferNo, unsigned int IntPageAdr, unsigned int No_of_bytes, unsigned char *BufferPtr)

{

	unsigned int i;
	unsigned char k;


	SPI_PORT |=(1<< SPI_CS);
	
	SPI_PORT &= ~(1<< SPI_CS);								//to reset dataflash command decoder

	

	if (1 == BufferNo)							//read byte(s) from buffer 1

	{

		k = SPI_transmit(0xd4);//Single Byte 0x00 to be sent to initiate read.
	
		k = SPI_transmit(0x00);
	
		k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
		k = SPI_transmit((unsigned char)IntPageAdr);
	
		k = SPI_transmit(0x00)	;					//don't cares

		for( i=0; i<No_of_bytes; i++)

		{

			*(BufferPtr) = SPI_receive();		//read byte and put it in AVR buffer pointed to by *BufferPtr

			BufferPtr++;						//point to next element in AVR buffer

		}

	}

	else

	if (2 == BufferNo)							//read byte(s) from buffer 2

	{

		k = SPI_transmit(0xd6);//Single Byte 0x00 to be sent to initiate read.
	
		k = SPI_transmit(0x00);
	
		k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
		k = SPI_transmit((unsigned char)IntPageAdr);
	
		k = SPI_transmit(0x00)	;					//don't cares

		for( i=0; i<No_of_bytes; i++)

		{

			*(BufferPtr) = SPI_receive();		//read byte and put it in AVR buffer pointed to by *BufferPtr

			BufferPtr++;						//point to next element in AVR buffer

		}
	}

}




/*****************************************************************************

*

*	Function name : Buffer_Write_Enable

*

*	Returns :		None

*

*	Parameters :	IntPageAdr	->	Internal page address to start writing from

*					BufferAdr	->	Decides usage of either buffer 1 or 2

*					

*	Purpose :		Enables continous write functionality to one of the dataflash buffers

*					buffers. NOTE : User must ensure that CS goes high to terminate

*					this mode before accessing other dataflash functionalities 

*

******************************************************************************/

void Buffer_Write_Enable (unsigned char BufferNo, unsigned int IntPageAdr)

{

	SPI_PORT |=(1<< SPI_CS);
	
	SPI_PORT &= ~(1<< SPI_CS);								//to reset dataflash command decoder

	unsigned char k;

	if (1 == BufferNo)							//write enable to buffer 1

	{
	k = SPI_transmit(0x84);
	
	k = SPI_transmit(0x00);
	
	k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
	k = SPI_transmit((unsigned char)IntPageAdr);
	
		//lower part of internal buffer address

	}

	else

	if (2 == BufferNo)							//write enable to buffer 2

	{
	k = SPI_transmit(0x87);
	
	k = SPI_transmit(0x00);
	
	k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
	k = SPI_transmit((unsigned char)IntPageAdr);

	}

}



/*****************************************************************************

*

*	Function name : Buffer_Write_Byte

*

*	Returns :		None

*

*	Parameters :	IntPageAdr	->	Internal page address to write byte to

*					BufferAdr	->	Decides usage of either buffer 1 or 2

*					Data		->	Data byte to be written

*

*	Purpose :		Writes one byte to one of the dataflash

*					internal SRAM buffers

*

******************************************************************************/

void Buffer_Write_Byte (unsigned char BufferNo, unsigned int IntPageAdr, unsigned char data)

{
	unsigned char k;
	

	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);						//to reset dataflash command decoder

	

	if (1 == BufferNo)							//write byte to buffer 1

	{

		k = SPI_transmit(0x84);
	
		k = SPI_transmit(0x00);
	
		k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
		k = SPI_transmit((unsigned char)IntPageAdr);
	
		k = SPI_transmit(data);						//write data byte

	}

	else

	if (2 == BufferNo)							//write byte to buffer 2

	{

		k = SPI_transmit(0x87);
	
		k = SPI_transmit(0x00);
	
		k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
		k = SPI_transmit((unsigned char)IntPageAdr);
	
		k = SPI_transmit(data);							//write data byte

	}	
		
		SPI_PORT |=(1<< SPI_CS);	
		/*SPI_PORT &= ~(1<< SPI_CS);
		k = send_status();
		while(!((k==0xAC)|(k==0xEC)))
		{
		//transmitString1("Error in writing byte");
		k = send_status();
		transmitByte1(k);
		_delay_ms(200);
		_delay_ms(200);
		_delay_ms(200);
		_delay_ms(200);
		}
		SPI_PORT |=(1<< SPI_CS);*/
}


/*****************************************************************************

*

*	Function name : Buffer_Write_Str

*

*	Returns :		None

*

*	Parameters :	BufferNo	->	Decides usage of either buffer 1 or 2

*					IntPageAdr	->	Internal page address

*					No_of_bytes	->	Number of bytes to be written

*					*BufferPtr	->	address of buffer to be used for copy of bytes

*									from AVR buffer to dataflash buffer 1 (or 2)

*

*	Purpose :		Copies one or more bytes to one of the dataflash

*					internal SRAM buffers from AVR SRAM buffer

*					pointed to by *BufferPtr

*

******************************************************************************/

void Buffer_Write_Str (unsigned char BufferNo, unsigned int IntPageAdr, unsigned int No_of_bytes, unsigned char *BufferPtr)

{

	unsigned int i;
	unsigned char k;

	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);								//to reset dataflash command decoder

	

	if (1 == BufferNo)							//write byte(s) to buffer 1

	{

		k = SPI_transmit(0x84);
	
		k = SPI_transmit(0x00);
	

		k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
		k = SPI_transmit((unsigned char)IntPageAdr);

		for( i=0; i<No_of_bytes; i++)

		{

			SPI_transmit(*(BufferPtr));//DF_SPI_RW(*(BufferPtr));			//write byte pointed at by *BufferPtr to dataflash buffer 1 location

			BufferPtr++;						//point to next element in AVR buffer

		}

	}

	else

	if (2 == BufferNo)							//write byte(s) to buffer 2

	{

		k = SPI_transmit(0x87);
	
		k = SPI_transmit(0x00);
	
		k = SPI_transmit((unsigned char)(IntPageAdr>>8));
	
		k = SPI_transmit((unsigned char)IntPageAdr);	//lower part of internal buffer address

		for( i=0; i<No_of_bytes; i++)

		{

			SPI_transmit(*(BufferPtr));//DF_SPI_RW(*(BufferPtr));			//write byte pointed at by *BufferPtr to dataflash buffer 2 location

			BufferPtr++;						//point to next element in AVR buffer

		}

	}

}





/*****************************************************************************

*

*	Function name : Buffer_To_Page

*

*	Returns :		None

*

*	Parameters :	BufferAdr	->	Decides usage of either buffer 1 or 2

*					PageAdr		->	Address of flash page to be programmed

*

*	Purpose :		Transfers a page from dataflash SRAM buffer to flash

*					

******************************************************************************/

void Buffer_To_Page (unsigned char BufferNo, unsigned int PageAdr)

{

	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);
	unsigned char k;	

	if (1 == BufferNo)											//program flash page from buffer 1

	{
	
	SPI_PORT &= ~(1<< SPI_CS);
	k = SPI_transmit(0x83);
	
	k = SPI_transmit((unsigned char)(PageAdr>>6));
	
	k = SPI_transmit((unsigned char)(PageAdr<<2));

	k = SPI_transmit(0x00);
	
	SPI_PORT |=(1<< SPI_CS);
	
	}

	else	

	if (2 == BufferNo)											//program flash page from buffer 2

	{

	SPI_PORT &= ~(1<< SPI_CS);
	k = SPI_transmit(0x86);
	
	k = SPI_transmit((unsigned char)(PageAdr>>6));
	
	k = SPI_transmit((unsigned char)(PageAdr<<2));

	k = SPI_transmit(0x00);
	
	SPI_PORT |=(1<< SPI_CS);										//don't cares

	}

	SPI_PORT &= ~(1<< SPI_CS);
	/*k = send_status();
	while(!((k==0xAC)|(k==0xEC)))
	{
	transmitString1("Error in buffer to page");
	k = send_status();
	_delay_ms(200);
	
	}*/
	SPI_PORT |=(1<< SPI_CS);
						//monitor the status register, wait until busy-flag is high

}




/*****************************************************************************
*
*	Function name : Cont_Flash_Read_Enable

*

*	Returns :		None

*

*	Parameters :			PageAdr		->	Address of flash page where cont.read starts from

*					IntPageAdr	->	Internal page address where cont.read starts from

*

*	Purpose :		Initiates a continuous read from a location in the DataFlash
*					
******************************************************************************/
/* have to check the errors creeping in
void Cont_Flash_Read_Enable (unsigned int PageAdr, unsigned int IntPageAdr)

{

	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);																//to 	reset dataflash command decoder
	unsigned char k;
	
	k = SPI_transmit(0x68);
														//Continuous Array Read op-code

	DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));						//upper part of page address

	DF_SPI_RW((unsigned char)((PageAdr << (PageBits - 8))+ (IntPageAdr>>8)));	//lower part of page address and MSB of int.page adr.

	DF_SPI_RW((unsigned char)(IntPageAdr));										//LSB byte of internal page address

	DF_SPI_RW(0x00);															//perform 4 dummy     writes

	DF_SPI_RW(0x00);															//in order to intiate DataFlash

	DF_SPI_RW(0x00);															//address pointers

	DF_SPI_RW(0x00);

}
 
*/
void write_to_flash(unsigned char flash_data)
{
	static unsigned int buffer_counter;
	static unsigned int page_counter;

	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);

	unsigned char j,k,l,status;
	j = send_status();
	
		while(!((j==0xAC)|(j==0xEC)))
		{
		transmitString1("Error");
		j = send_status();
		
		}
		
	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);
	
	k = SPI_transmit(0x84);
	
	k = SPI_transmit(0x00);
	
	k = SPI_transmit((unsigned char)(buffer_counter>>8));
	
	k = SPI_transmit((unsigned char)buffer_counter);
	
	k = SPI_transmit(flash_data);
	
	SPI_PORT |=(1<< SPI_CS);	
	SPI_PORT &= ~(1<< SPI_CS);

		j = send_status();
		while(!((j==0xAC)|(j==0xEC)))
		{
		transmitString1("Error");
		j = send_status();
		}
	SPI_PORT |=(1<< SPI_CS);
	buffer_counter++;
			if (buffer_counter > 528)
		// if buffer full write buffer into memory page
			{
			buffer_counter = 0;
				if (page_counter < 4096)
		// if memory is not full
				{
				unsigned char k,j;
				SPI_PORT &= ~(1<< SPI_CS);
				k = SPI_transmit(0x88);
			
				k = SPI_transmit((unsigned char)(page_counter>>6));
		
				k = SPI_transmit((unsigned char)(page_counter<<2));

				k = SPI_transmit(0x00);
		
				SPI_PORT |=(1<< SPI_CS);
				SPI_PORT &= ~(1<< SPI_CS);
	
				j = send_status();
				//Used the following code for doing that
	/*write_SPI(B1_TO_MM_PAGE_PROG_WITHOUT_ERASE);// write data from buffer1 to page 
				write_SPI((char)(page_counter>>6));
				write_SPI((char)(page_counter<<2));
					write_SPI(0x00);*/ 	
				while(!((j==0xAC)|(j==0xEC)))
				{
				transmitString1("Error");
				j = send_status();
				_delay_ms(200);
		
				}
				page_counter++;
				}
		}
}

























